package cn.iocoder.yudao.adminserver.franky.LRU;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description:
 * @Author: franky
 * @CreateDate: 2021/4/15 5:34 下午
 * @Version: 1.0
 */
public class LRU {

    private Integer capacity;
    private Map<String, Nodes> lruMap;
    private Nodes head;
    private Nodes end;

    public LRU(Integer capacity) {
        this.capacity = capacity;
        lruMap = new ConcurrentHashMap<>();
    }

    public String get(String key) {
        Nodes node = lruMap.get(key);
        if (null == node) {
            return null;
        }
        refreshNode(node);
        return node.val;
    }

    public void add(String key, String val) {
        Nodes node = lruMap.get(key);
        if (node == null) {
            //新增需要判断是否回收
            if (lruMap.size() >= capacity) {
                lruMap.remove(head.key);
                removeNode(head);
            }
            node = new Nodes(key, val);
            addNode(node);
            return;
        }
        node.val = val;
        refreshNode(node);
    }


    public void remove(String key) {
        if (!lruMap.containsKey(key)) {
            lruMap.remove(key);
        }
    }

    private void refreshNode(Nodes node) {
        if (end == node) {
            return;
        }
        removeNode(node);
        addNode(node);
    }

    private void addNode(Nodes node) {
        if (end != null) {
            end.next = node;
            node.pre = end;
            node.next = null;
        }
        end = node;
        if (head == null) {
            head = node;
        }
    }

    private void removeNode(Nodes node) {
        if (head == node && end == node) {
            head = null;
            end = null;
        } else if (head == node) {
            head = head.next;
            head.pre = null;
        } else if (end == node) {
            end = end.pre;
            end.next = null;
        } else {
            node.pre.next = node.next;
            node.next.pre = node.pre;
        }
    }


    private class Nodes {
        private String key;
        private String val;
        private Nodes pre;
        private Nodes next;

        public Nodes(String key, String val) {
            this.key = key;
            this.val = val;
        }
    }

}
